/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Net;
using System.Text;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Client;
using Galaxium.Protocol;
using Galaxium.Protocol.Msn;

namespace Galaxium.PlusSounds
{
	public static class SoundHandler
	{
		static string _cacheDir;
		
		static SoundHandler ()
		{
			//TODO: Galaxium needs to expose the cache directory properly
			_cacheDir = Path.Combine (CoreUtility.GetConfigurationSubDirectory ("Cache"), "Plus! Sounds");
			
			BaseUtility.CreateDirectoryIfNeeded (_cacheDir);
		}
		
		public static void OnReceivedMessageActivity (object sender, ReceivedMessageActivity activity)
		{
			if (!(activity.Conversation is MsnConversation))
				return;
			
			string text = activity.Message.GetText ();
			
			if (text.StartsWith ("[Messenger Plus! Sound] - Data{"))
			{
				// This message is a custom sound
				
				try
				{
					string hash = text.Substring (31, text.IndexOf ("}") - 31);
					string name = text.Substring (text.IndexOf ("-", 30) + 1).Replace ("\n", "").Trim ();
					
					Log.Debug ("Messenger Plus! sound detected, name '{0}' hash {1}", name, hash);
					
					activity.Handled = true;
					
					// We emit an activity here so that a window is opened if necessary
					ActivityUtility.EmitActivity (null, new ReceivedSoundActivity (activity.Conversation, name, hash));
					
					string msg = string.Format ("{0} sent you the sound '{1}'", activity.Message.Source.DisplayIdentifier, name);
					(activity.Conversation as MsnConversation).EmitActionMessage (msg);
					
					string cacheFile = Path.Combine (_cacheDir, hash.ToUpper ());
					
					if (File.Exists (cacheFile))
						PlaySound (cacheFile);
					else
					{
						Uri src = new Uri ("http://sounds.msgpluslive.net/esnd/snd/get?hash=" + hash);
						
						Log.Debug ("Downloading sound from {0}", src.AbsoluteUri);
						
						WebRequest req = WebRequest.Create (src);
						req.BeginGetResponse (OnDownloadSoundComplete, req);
					}
				}
				catch
				{
					Log.Warn ("Unable to parse Messenger Plus! sound message");
				}
			}
			else if ((text.Length > 1) && (((byte)text[0]) == 4))
			{
				// This message is a 'built in' sound
				// although the sound is downloaded anyway
				
				Log.Debug ("Plus! Built in sound message {0}", BaseUtility.BytesToString (System.Text.Encoding.UTF8.GetBytes (text)));
				
				// Parse the message
				
				byte soundCode = (byte)text[1];
				
				int i = 2;
				StringBuilder msgText = new StringBuilder ();
				bool bold = false;
				string color = null;
				
				while (i < text.Length)
				{
					char ch = text[i];
					
					switch (ch)
					{
					case (char)2: // Bold
						bold = !bold;
						msgText.Append (bold ? "[b]" : "[/b]");
						break;
					case (char)3: // Color
						string col = string.Empty;
						while (((i + 1) < text.Length) && char.IsDigit (text[i + 1]))
						{
							col += text[i + 1];
							i++;
						}
						msgText.Append ((string.IsNullOrEmpty (color) ? "[c" : "[/c") +
						                (string.IsNullOrEmpty (col) ? string.Empty : "=" + col) +
						                "]");
						color = string.IsNullOrEmpty (color) ? col : null;
						break;
					default:
						msgText.Append (ch);
						break;
					}
					
					i++;
				}
				
				//Log.Debug ("Message text: '{0}'", msgText.ToString ());
				activity.Message.SetText (msgText.ToString ());
				
				// Handle the sound playback
				
				string cacheFile = Path.Combine (_cacheDir, soundCode.ToString ());
				
				if (File.Exists (cacheFile))
					PlaySound (cacheFile);
				else
				{
					Uri src = new Uri ("http://sounds.msgpluslive.net/esnd/snd/builtin?code=" + soundCode.ToString ());
					
					Log.Debug ("Downloading sound from {0}", src.AbsoluteUri);
						
					WebRequest req = WebRequest.Create (src);
					req.BeginGetResponse (OnDownloadSoundComplete, req);
				}
			}
		}
		
		static void OnDownloadSoundComplete (IAsyncResult asyncResult)
		{
			WebRequest req = asyncResult.AsyncState as WebRequest;
			
			try
			{
				WebResponse response = req.EndGetResponse (asyncResult);
				Stream stream = response.GetResponseStream ();
				
				string hash = response.ResponseUri.AbsoluteUri.Substring (response.ResponseUri.AbsoluteUri.LastIndexOf ('=') + 1);
				string cacheFile = Path.Combine (_cacheDir, hash);
				
				FileStream fileStream = File.OpenWrite (cacheFile);
				
				byte[] buf = new byte[256];
				int len;
				
				while ((len = stream.Read (buf, 0, buf.Length)) > 0)
				{
					fileStream.Write (buf, 0, len);
					//Log.Debug ("Downloaded {0} bytes", fileStream.Length);
				}
				
				Log.Debug ("Sound Downloaded ({0} bytes)", fileStream.Length);
				
				fileStream.Close ();
				
				PlaySound (cacheFile);
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Error Downloading Sound");
			}
		}
		
		static void PlaySound (string filename)
		{
			ISoundPlayer player = SoundUtility.Open (filename);
			
			player.Error += delegate
			{
				Log.Error ("Playback error, removing sound from cache");
				
				if (File.Exists (filename))
					File.Delete (filename);
			};
			player.EndOfStream += delegate
			{
				player.Stop ();
				player.Dispose ();
			};
			player.Play ();
		}
	}
}
